# Python面向对象编程：类的属性和方法详解

"""
本节详细介绍Python类中的各种属性和方法：
1. 类属性：直接在类中定义的属性，被所有实例共享
2. 实例属性：在构造函数中定义的属性，每个实例独有
3. 实例方法：普通的对象方法，可以访问实例属性和类属性
4. 类方法：使用@classmethod装饰器，可以访问类属性
5. 静态方法：使用@staticmethod装饰器，不能访问类属性和实例属性

每种属性和方法都有其适用场景，本示例将通过Student类来演示。
"""


class Student:
    # 类属性：被所有实例共享的属性
    # 适用场景：
    # 1. 所有实例都相同的属性（如学校名称）
    # 2. 需要被所有实例共享的计数器或配置
    # 3. 常量值或默认值
    school_name = "Python编程学校"  # 所有学生都属于这个学校
    student_count = 0  # 用于统计学生总数的计数器

    def __init__(self, name, age):
        """构造函数：初始化实例属性
        实例属性：每个实例独有的属性
        适用场景：
        1. 每个实例都不同的属性（如姓名、年龄）
        2. 需要在创建实例时初始化的属性
        3. 实例特有的状态或数据
        4. 实例属性也可以在其他实例方法中动态添加和修改
        """
        self.name = name  # 实例属性：姓名
        self.age = age  # 实例属性：年龄
        Student.student_count += 1  # 学生计数器加1
        # 注意：虽然可以在其他实例方法中添加实例属性
        # 但建议在__init__中集中定义所有需要的实例属性
        # 这样可以提高代码的可读性和可维护性

    def study(self, subject):
        """实例方法：普通的对象方法
        适用场景：
        1. 需要访问/修改实例属性的操作
        2. 实例特有的行为或功能
        3. 需要根据实例状态执行的操作
        """
        # 通过 self. 可以访问实例属性和类属性
        print(f"{self.name}正在{self.school_name}学习{subject}")

    @classmethod
    def get_student_count(cls):
        """类方法：使用@classmethod装饰器
        第一个参数通常是 cls ，代表类本身
        适用场景：
        1. 需要访问/修改类属性的操作
        2. 与实例无关的类级别的操作
        3. 作为构造函数的替代方法，实现不同的实例化方式
        """
        print(f"当前学生总数：{cls.student_count}人")
        return cls.student_count

    @staticmethod
    def check_age(age):
        """静态方法：使用@staticmethod装饰器
        第一个参数无需传入self或cls
        适用场景：
        1. 不需要访问类属性和实例属性的工具方法
        2. 与类逻辑相关但不依赖类状态的方法
        3. 放在类中便于组织的功能性方法
        """
        if isinstance(age, int) and 0 <= age <= 120:
            return True
        return False


# 演示各种方法和属性的使用
if __name__ == "__main__":
    # 使用静态方法验证年龄
    print("===== 静态方法演示 =====")
    # 直接用类名.就可以调用静态方法，无需创建实例
    print("年龄18是否合法：", Student.check_age(18))  # True
    print("年龄-1是否合法：", Student.check_age(-1))  # False

    # 创建学生实例
    print("\n===== 创建学生实例 =====")
    student1 = Student("张三", 18)
    student2 = Student("李四", 19)

    # 调用实例方法
    print("\n===== 实例方法演示 =====")
    student1.study("Python")
    student2.study("数据结构")

    # 访问类属性
    print("\n===== 类属性演示 =====")
    print(f"学校名称：{Student.school_name}")

    # 调用类方法
    print("\n===== 类方法演示 =====")
    Student.get_student_count()

"""
总结：在实际开发中选择合适的属性和方法类型：

1. 类属性：
   - 用于存储所有实例共享的数据
   - 用于实现计数器或配置信息
   - 存储类级别的默认值或常量

2. 实例属性：
   - 用于存储每个实例独特的数据
   - 在构造函数中初始化
   - 可以在实例方法中修改

3. 实例方法：
   - 实现对象的行为和功能
   - 需要访问实例属性时使用
   - 代表对象可以执行的操作

4. 类方法：
   - 实现与类相关的功能
   - 需要访问类属性时使用
   - 实现替代构造函数或类级别的操作

5. 静态方法：
   - 实现与类相关但不需要访问类属性和实例属性的功能
   - 用于实现工具方法或辅助功能
   - 主要用于代码组织和模块化

选择原则：
1. 如果方法需要访问实例属性 -> 使用实例方法
2. 如果方法只需要访问类属性 -> 使用类方法
3. 如果方法不需要访问任何属性 -> 使用静态方法
4. 如果属性需要被所有实例共享 -> 使用类属性
5. 如果属性属于特定实例 -> 使用实例属性
"""
